/*******************************************************************************
*                                    ZLG
*                         ----------------------------
*                         innovating embedded platform
*
* Copyright (c) 2001-2021 Guangzhou ZHIYUAN Electronics Co., Ltd.
* All rights reserved.
*
* Contact information:
* web site:    https://www.zlg.cn
*******************************************************************************/
#ifndef __HC32F4A0_CLK_H
#define __HC32F4A0_CLK_H

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus*/
#include "hc32f4a0_regs_cmu.h"
#include "hc32f4a0_regs_pwc.h"

/* \brief HC32F4A0 切换时钟源等待稳定时间(基于240M频率的30微秒)*/
#define CLK_SYSCLK_SW_STABLE         (0x200)

#define CLK_XTAL_TIMEOUT             ((uint32_t)0x1000)
#define CLK_XTAL32_TIMEOUT           ((uint32_t)0x1000)
#define CLK_HRC_TIMEOUT              ((uint32_t)0x1000)
#define CLK_MRC_TIMEOUT              ((uint32_t)0x1000)
#define CLK_LRC_TIMEOUT              ((uint32_t)0x1000)
#define CLK_PLLH_TIMEOUT             ((uint32_t)0x1000)
#define CLK_PLLA_TIMEOUT             ((uint32_t)0x1000)

/* \brief HC32F4A0 时钟频率*/
#define HRC_16MHz_VALUE              ((uint32_t)16000000)  /* 内部高速RC频率(16MHz) */
#define HRC_20MHz_VALUE              ((uint32_t)20000000)  /* 内部高速RC频率(20MHz) */
#define MRC_VALUE                    ((uint32_t)8000000)   /* 内部中速RC频率(8MHz)*/
#define LRC_VALUE                    ((uint32_t)32768)     /* 内部低速RC频率(32.768KHz)*/
#define XTAL32_VALUE                 ((uint32_t)32768)     /* 外部低速OSC频率(32.768KHz)*/

/* \brief HC32F4A0 时钟选择*/
#define CLK_CATE_PCLK0                (0x01)
#define CLK_CATE_PCLK1                (0x02)
#define CLK_CATE_PCLK2                (0x04)
#define CLK_CATE_PCLK3                (0x08)
#define CLK_CATE_PCLK4                (0x10)
#define CLK_CATE_EXCLK                (0x20)
#define CLK_CATE_HCLK                 (0x40)
#define CLK_CATE_ALL                  (CLK_CATE_PCLK0 | CLK_CATE_PCLK1 | CLK_CATE_PCLK2 | \
                                       CLK_CATE_PCLK3 | CLK_CATE_PCLK4 | CLK_CATE_EXCLK | \
                                       CLK_CATE_HCLK)

/* \biref HC32F4A0 系统时钟源选择*/
#define CLK_SYSCLKSOURCE_HRC          (0x00)   /* 系统时钟源为内部高速RC*/
#define CLK_SYSCLKSOURCE_MRC          (0x01)   /* 系统时钟源为内部中速RC*/
#define CLK_SYSCLKSOURCE_LRC          (0x02)   /* 系统时钟源为内部低速RC*/
#define CLK_SYSCLKSOURCE_XTAL         (0x03)   /* 系统时钟源为外部高速OSC*/
#define CLK_SYSCLKSOURCE_XTAL32       (0x04)   /* 系统时钟源为外部低速OSC*/
#define CLK_SYSCLKSOURCE_PLLH         (0x05)   /* 系统时钟源为PLLH*/

/* \brief PLLH 功能配置*/
#define CLK_PLLH_OFF                  (CMU_PLLHCR_PLLHOFF)
#define CLK_PLLH_ON                   (0x00)

/* \brief PLLH/A 时钟源选择*/
#define CLK_PLLSRC_XTAL               (0x00)
#define CLK_PLLSRC_HRC                (0x01)

/* \brief HC32F4A0 HCLK 时钟分频系数*/
#define CLK_HCLK_DIV1                 (0x00 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV2                 (0x01 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV4                 (0x02 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV8                 (0x03 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV16                (0x04 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV32                (0x05 << CMU_SCFGR_HCLKS_POS)
#define CLK_HCLK_DIV64                (0x06 << CMU_SCFGR_HCLKS_POS)

/* \brief HC32F4A0 EXCLK 时钟分频系数*/
#define CLK_EXCLK_DIV1                (0x00 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV2                (0x01 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV4                (0x02 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV8                (0x03 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV16               (0x04 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV32               (0x05 << CMU_SCFGR_EXCKS_POS)
#define CLK_EXCLK_DIV64               (0x06 << CMU_SCFGR_EXCKS_POS)

/* \brief HC32F4A0 PCLK0 时钟分频系数*/
#define CLK_PCLK0_DIV1                (0x00 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV2                (0x01 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV4                (0x02 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV8                (0x03 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV16               (0x04 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV32               (0x05 << CMU_SCFGR_PCLK0S_POS)
#define CLK_PCLK0_DIV64               (0x06 << CMU_SCFGR_PCLK0S_POS)

/* \brief HC32F4A0 PCLK1 时钟分频系数*/
#define CLK_PCLK1_DIV1                (0x00 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV2                (0x01 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV4                (0x02 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV8                (0x03 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV16               (0x04 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV32               (0x05 << CMU_SCFGR_PCLK1S_POS)
#define CLK_PCLK1_DIV64               (0x06 << CMU_SCFGR_PCLK1S_POS)

/* \brief HC32F4A0 PCLK2 时钟分频系数*/
#define CLK_PCLK2_DIV1                (0x00 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV2                (0x01 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV4                (0x02 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV8                (0x03 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV16               (0x04 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV32               (0x05 << CMU_SCFGR_PCLK2S_POS)
#define CLK_PCLK2_DIV64               (0x06 << CMU_SCFGR_PCLK2S_POS)

/* \brief HC32F4A0 PCLK3 时钟分频系数*/
#define CLK_PCLK3_DIV1                (0x00 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV2                (0x01 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV4                (0x02 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV8                (0x03 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV16               (0x04 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV32               (0x05 << CMU_SCFGR_PCLK3S_POS)
#define CLK_PCLK3_DIV64               (0x06 << CMU_SCFGR_PCLK3S_POS)

/* \brief HC32F4A0 PCLK4 时钟分频系数*/
#define CLK_PCLK4_DIV1                (0x00 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV2                (0x01 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV4                (0x02 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV8                (0x03 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV16               (0x04 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV32               (0x05 << CMU_SCFGR_PCLK4S_POS)
#define CLK_PCLK4_DIV64               (0x06 << CMU_SCFGR_PCLK4S_POS)

/* \brief 检查时钟源 */
#define IS_CLK_CATE(cate)           (((cate) & CLK_CATE_ALL) != (uint8_t)(0x00U))
/* \brief 检查时钟寄存器锁状态 */
#define IS_CLK_UNLOCKED()            ((HC32F4A0_PWC->FPRC & PWC_FPRC_FPRCB0) == PWC_FPRC_FPRCB0)
/* \brief PLLH 状态参数有效检查*/
#define IS_CLK_PLLH_STATE(sta)      (((sta) == CLK_PLLH_OFF) || ((sta) == CLK_PLLH_ON))
/* \brief 检查 HCLK 分频参数 */
#define IS_CLK_HCLK_DIV(div)        (((div) == CLK_HCLK_DIV1)  || ((div) == CLK_HCLK_DIV2)  ||   \
                                     ((div) == CLK_HCLK_DIV4)  || ((div) == CLK_HCLK_DIV8)  ||   \
                                     ((div) == CLK_HCLK_DIV16) || ((div) == CLK_HCLK_DIV32) ||   \
                                     ((div) == CLK_HCLK_DIV64))
/* \brief 检查 PCLK0 分频参数 */
#define IS_CLK_PCLK0_DIV(div)       (((div) == CLK_PCLK0_DIV1)  || ((div) == CLK_PCLK0_DIV2)  || \
                                     ((div) == CLK_PCLK0_DIV4)  || ((div) == CLK_PCLK0_DIV8)  || \
                                     ((div) == CLK_PCLK0_DIV16) || ((div) == CLK_PCLK0_DIV32) || \
                                     ((div) == CLK_PCLK0_DIV64))
/* \brief 检查 PCLK1 分频参数 */
#define IS_CLK_PCLK1_DIV(div)       (((div) == CLK_PCLK1_DIV1)  || ((div) == CLK_PCLK1_DIV2)  || \
                                     ((div) == CLK_PCLK1_DIV4)  || ((div) == CLK_PCLK1_DIV8)  || \
                                     ((div) == CLK_PCLK1_DIV16) || ((div) == CLK_PCLK1_DIV32) || \
                                     ((div) == CLK_PCLK1_DIV64))
/* \brief 检查 PCLK2 分频参数 */
#define IS_CLK_PCLK2_DIV(div)       (((div) == CLK_PCLK2_DIV1)  || ((div) == CLK_PCLK2_DIV2)  || \
                                     ((div) == CLK_PCLK2_DIV4)  || ((div) == CLK_PCLK2_DIV8)  || \
                                     ((div) == CLK_PCLK2_DIV16) || ((div) == CLK_PCLK2_DIV32) || \
                                     ((div) == CLK_PCLK2_DIV64))
/* \brief 检查 PCLK3 分频参数 */
#define IS_CLK_PCLK3_DIV(div)       (((div) == CLK_PCLK3_DIV1)  || ((div) == CLK_PCLK3_DIV2)  || \
                                     ((div) == CLK_PCLK3_DIV4)  || ((div) == CLK_PCLK3_DIV8)  || \
                                     ((div) == CLK_PCLK3_DIV16) || ((div) == CLK_PCLK3_DIV32) || \
                                     ((div) == CLK_PCLK3_DIV64))
/* \brief 检查 PCLK4 分频参数 */
#define IS_CLK_PCLK4_DIV(div)       (((div) == CLK_PCLK4_DIV1)  || ((div) == CLK_PCLK4_DIV2)  || \
                                     ((div) == CLK_PCLK4_DIV4)  || ((div) == CLK_PCLK4_DIV8)  || \
                                     ((div) == CLK_PCLK4_DIV16) || ((div) == CLK_PCLK4_DIV32) || \
                                     ((div) == CLK_PCLK4_DIV64))
/* \brief 检查 EXCLK 分频参数 */
#define IS_CLK_EXCLK_DIV(div)       (((div) == CLK_EXCLK_DIV1)  || ((div) == CLK_EXCLK_DIV2)  ||  \
                                     ((div) == CLK_EXCLK_DIV4)  || ((div) == CLK_EXCLK_DIV8)  ||  \
                                     ((div) == CLK_EXCLK_DIV16) || ((div) == CLK_EXCLK_DIV32) ||  \
                                     ((div) == CLK_EXCLK_DIV64))
/* \brief 检查 PLLH 输入源参数 */
#define IS_CLK_PLL_SRC(src)         (((src) == CLK_PLLSRC_XTAL) || ((src) == CLK_PLLSRC_HRC))
/* \brief 检查 PLLH M 分频参数 */
#define IS_CLK_PLLHM_DIV(m)          ((CLK_PLLHM_DIV_MIN <= (m)) && (CLK_PLLHM_DIV_MAX >= (m)))
/* \brief 检查 PLLH N 倍频参数 */
#define IS_CLK_PLLHN_MULTI(n)        ((CLK_PLLHN_MULTI_MIN <= (n)) && (CLK_PLLHN_MULTI_MAX >= (n)))
/* \brief 检查 PLLH R 分频参数 */
#define IS_CLK_PLLHR_DIV(r)          ((CLK_PLLHR_DIV_MIN <= (r)) && (CLK_PLLHR_DIV_MAX >= (r)))
/* \brief 检查 PLLH Q 分频参数 */
#define IS_CLK_PLLHQ_DIV(q)          ((CLK_PLLHQ_DIV_MIN <= (q)) && (CLK_PLLHQ_DIV_MAX >= (q)))
/* \brief 检查 PLLH P 分频参数 */
#define IS_CLK_PLLHP_DIV(p)          ((CLK_PLLHP_DIV_MIN <= (p)) && (CLK_PLLHP_DIV_MAX >= (p)))
/* \brief 检查 PLLH 频率 */
#define IS_CLK_PLLH_FREQ(freq)       ((CLK_PLLH_FREQ_MIN <= (freq)) && (CLK_PLLH_FREQ_MAX >= (freq)))
/* \brief 检查 VCO IN 有效性 */
#define IS_CLK_PLLH_VCO_IN(vco_in)   ((CLK_PLLH_VCO_IN_MIN <= (vco_in)) &&   \
                                      (CLK_PLLH_VCO_IN_MAX >= (vco_in)))
/* \brief 检查 VCO OUT 有效性 */
#define IS_CLK_PLLH_VCO_OUT(vco_out) ((CLK_PLLH_VCO_OUT_MIN <= (vco_out)) &&  \
                                      (CLK_PLLH_VCO_OUT_MAX >= (vco_out)))

/* \brief HC32F4A0 PLL时钟配置结构体*/
struct hc32f4a0_clk_pll {
    uint8_t          pll_sta;     /* PLLH状态*/

    union {
        uint32_t     pll_cfg_r;   /* PLL配置寄存器 */
        struct {
            uint32_t pll_m   :2;  /* PLLH/PLLA分频系数 */
            uint32_t resvd0 :5;   /* 保留*/
            uint32_t pll_src :1;  /* PLLH/PLLA时钟源选择*/
            uint32_t pll_n   :8;  /* PLLH/PLLA倍频系数 */
            uint32_t resvd1 :4;   /* 保留*/
            uint32_t pll_r   :4;  /* PLLR分频系数，PLLR输出 = VCO/PLLR*/
            uint32_t pll_q   :4;  /* PLLQ分频系数，PLLQ输出 = VCO/PLLQ*/
            uint32_t pll_p   :4;  /* PLLP分频系数，PLLP输出 = VCO/PLLP*/
        } pll_cfg_r_f;
    };
};

/**
 * \brief 系统外围设备写使能
 */
void sys_peripheral_we(void);
/**
 * \brief 系统外围设备写保护
 */
void sys_peripheral_wp(void);
/**
 * \brief 获取 PCLK 时钟
 */
uint32_t sys_clk_pclk_get(void);
/**
 * \brief 获取 HCLK 时钟
 */
uint32_t sys_clk_hclk_get(void);
/**
 * \brief 获取系统核心时钟
 */
uint32_t sys_clk_core_get(void);
/**
 * \brief 设置外部晶振频率
 */
void sys_clk_xtal_set(uint32_t xtal_freq);
/**
 * \brief 初始化 PLLH
 */
int sys_clk_pllh_init(const struct hc32f4a0_clk_pll *p_pllh_cfg);
/**
 * \brief HC32f4a0 HCLK/PCLK 时钟分频设置
 */
int sys_clk_div_set(uint8_t clk_cate, uint32_t div);
/**
 * \brief 设置系统时钟源
 */
void sys_clk_src_set(uint8_t clk_src);
/**
 * \brief 时钟反初始化
 */
void sys_clk_reg_recover(void);
/**
 * \brief 时钟寄存器值备份
 */
void sys_clk_reg_backup(void);
#ifdef __cplusplus
}
#endif  /* __cplusplus  */


#endif




